home *** CD-ROM | disk | FTP | other *** search
/ The Atari Compendium / The Atari Compendium (Toad Computers) (1994).iso / files / prgtools / mint / filesy~1 / mfs610s.zoo / minixfs / minixfs.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-05-12  |  35.8 KB  |  1,507 lines

  1. /* This file is part of 'minixfs' Copyright 1991,1992,1993,1994 S.N.Henson */
  2.  
  3. #include "minixfs.h"
  4. #include "proto.h"
  5. #include "global.h"
  6.  
  7. FILESYS minix_filesys = {
  8.     (FILESYS *) 0,
  9.     FS_CASESENSITIVE | FS_LONGPATH,
  10.     m_root, m_lookup, m_creat, m_getdev,
  11.     m_getxattr, m_chattr, m_chown,
  12.     m_chmode, m_mkdir,
  13.     m_rmdir, m_remove, m_getname,
  14.     m_rename, m_opendir, m_readdir,
  15.     m_rewinddir, m_closedir,
  16.     m_pathconf, m_dfree,
  17.     m_wlabel, m_rlabel,
  18.     m_symlink, m_readlink,
  19.     m_hardlink, m_fscntl, m_dskchng,
  20.     m_release,m_dupcookie
  21. };
  22.  
  23. extern DEVDRV minix_dev;
  24.  
  25. static restore_dev=-1;
  26.  
  27. /*
  28.  * the kernel calls this when it detects a disk change. Note the mnt_flags
  29.  * flag MNT_CHANGE signals that the drive is being changed to force relogging
  30.  * of it's root directory and it should not be completely changed.
  31.  */
  32.  
  33. /*
  34.  * Hack alert: disk changes on mounted filesystems are ungracefully handled.
  35.  * Basically, if it isn't the first forced change then they are ignored. See
  36.  * comment (3) in #if does_not_work_yet for reason. This isn't any great loss
  37.  * because changing mounted filesystems is very naughty (causing various Unix
  38.  * variants to panic, in more senses than one. If Unix doesn't handle it why
  39.  * should I? ). Actually since changes, by necessity force the mounted 
  40.  * structure to be destroyed, there isn't much we can gracefully do.
  41.  */
  42.  
  43. long m_dskchng(d)
  44. int d;
  45. {
  46.     FILEPTR *f, **last;
  47.     super_info *psblk;
  48.     char ignore;
  49.     psblk=super_ptr[d];
  50.  
  51.     TRACE("Disk Change drive %c",d+'A');
  52.  
  53.     if(psblk && psblk!=DFS)
  54.     {
  55.         ignore = psblk->mnt_flags & MNT_CHANGE;
  56.         /* If mounted then (for now) ignore changes */
  57.         if(!ignore && psblk->mnt_inode) return 0;
  58.     }
  59.     else ignore=0;
  60.  
  61.     if(psblk && psblk!=DFS && !ignore)
  62.     {
  63.         Kfree(psblk->ibitmap);
  64.  
  65. #if does_not_work_yet
  66.  
  67.         /* Need to do three things:
  68.          * 1. Make sure all children are no longer mounted.
  69.          * 2. Make sure filesystem is no longer searched in lookups
  70.          *    of parent device.
  71.          * 3. (sigh) Force media change of all descendents without
  72.          *    disturbing mounted structure, so MiNT will reread the
  73.          *    root dirs properly.
  74.          */
  75.  
  76.         if(psblk->mnt_inode)
  77.         /* Umount this filesystem */
  78.         {
  79.           super_info **ublk,*tsblk;
  80.           /* Unlink from list on parent device */
  81.           for(ublk=&super_ptr[psblk->mnt_dev]->mnt_first;*ublk;
  82.                               ublk=&(*ublk)->mnt_next)
  83.             if(*ublk==psblk)
  84.             {
  85.             *ublk=psblk->mnt_next;
  86.             break;
  87.             }
  88.             /* Umount all children */
  89.             for(tsblk=psblk->mnt_first;tsblk;tsblk=tsblk->mnt_next)
  90.                                  tsblk->mnt_inode=0;
  91.         }
  92. #endif
  93.         Kfree(psblk);
  94.     }
  95.     if(!ignore) super_ptr[d]=0;
  96.  
  97.     /* this may affect the m_getname cache, too */
  98.     if (lpath && (d == lroot.dev || d == ldir.dev)) {
  99.         Kfree(lpath);
  100.         lpath = 0;
  101.     }
  102.  
  103.     /* Since the disk has changed always invalidate cache */
  104.     m_invalidate(d);
  105.  
  106.     /* Free any memory associated to file pointers of this drive. */
  107.     last = &firstptr;
  108.     for (f = *last; f != 0; f = *last)
  109.       {
  110.         if (f->fc.dev == d)
  111.           {
  112.         f_cache *fch = (f_cache *) f->devinfo;
  113.         /* The lock structure is shared between the fileptr's.
  114.            Make sure that it is freed only once. */
  115.         if (!f->next || f->next->fc.dev != d
  116.             || f->next->fc.index != f->fc.index)
  117.           {
  118.             LOCK *lck, *nextlck;
  119.             nextlck = *fch->lfirst;
  120.             while ((lck = nextlck) != 0)
  121.               {
  122.             nextlck = lck->next;
  123.             Kfree (lck);
  124.               }
  125.             Kfree (fch->lfirst);
  126.           }
  127.         Kfree (fch);
  128.         /* Remove this fileptr from the list. */
  129.         *last = f->next;
  130.         f->next = 0;
  131.           }
  132.         else
  133.           last = &f->next;
  134.       }
  135.         
  136.     if(!ignore) minix_sanity(d);
  137.  
  138.     return 1;
  139. }
  140.  
  141. /*
  142.  * Note: in the first round of initialisations, we assume that floppy
  143.  * drives (A and B) don't belong to us; but in a later disk change,
  144.  * they may very well be ours, so we remember that. This is means that a
  145.  * minix disk inserted into a drive will be unrecognisable at boot up and
  146.  * a forced disk change is needed. However for MiNT 1.05 (and presumably
  147.  * later) drives are initialised on first access so this isn't needed.
  148.  */
  149.  
  150. long m_root(dev,dir)
  151. int dev;
  152. fcookie *dir;
  153. {
  154.     int ret;
  155.     static first_init = 2;
  156.     extern FILESYS dummy_filesys;
  157.     super_info **psblk;
  158.  
  159.     psblk = super_ptr+dev;
  160.  
  161.     ret=0;
  162.  
  163.     if( (kernel->maj_version==0 ) || 
  164.         (kernel->maj_version==1 && kernel->min_version < 5 ) ) {
  165.         /* the first 2 checks (on A: and B:) we fail automatically */
  166.         if (first_init ) {
  167.             --first_init;
  168.             return -1;
  169.         }
  170.     }
  171.  
  172.     /* If not present, see if it's valid */
  173.     if( *psblk || ( dev >= 0 && (ret=minix_sanity(dev)) ) ) {
  174.         if(ret ==-1 || *psblk==DFS ) dir->fs = &dummy_filesys;
  175.         else
  176.         {
  177.             dir->fs=&minix_filesys;
  178.             /* Aux field tells original device */
  179.             dir->aux= dev | AUX_DRV ;
  180.             dir->index=ROOT_INODE;
  181.             /* If mounted trace back to root filesystem */
  182.             while((*psblk)->mnt_inode)
  183.             {
  184.                 dev=(*psblk)->mnt_dev;
  185.                 psblk=super_ptr+dev;
  186.             }
  187.         }
  188.         dir->dev=dev;
  189.         return 0;
  190.  
  191.     }
  192.     return -1;
  193. }
  194.  
  195. long m_lookup(dir,name,entry)
  196. fcookie *dir; 
  197. char *name;
  198. fcookie *entry;
  199. {
  200.  
  201.     if(!*name)
  202.     {
  203.         *entry=*dir;
  204.         entry->aux=0;
  205.         return 0;
  206.     }
  207.  
  208.     if(dir->index==ROOT_INODE && !strcmp(name,".."))
  209.     {
  210.         *entry=*dir;
  211.         /* If mounted treat as a lookup from mount point */
  212.         if( cross_mount(entry) ) return EMOUNT;
  213.         DEBUG("m_lookup: crossing mount point");
  214.         entry->index = search_dir(name,entry->index,entry->dev,FIND);
  215.         if(entry->index < 0 )  return entry->index;
  216.         entry->aux=0;
  217.         return 0;
  218.     }
  219.  
  220.     entry->index=search_dir(name,dir->index,dir->dev,FIND);
  221.     entry->dev=dir->dev;
  222.     if(entry->index < 0 ) return entry->index ;
  223.     entry->aux=0;
  224.     entry->fs=&minix_filesys;
  225.     if( check_mount(entry) ) DEBUG("Crossed mount point");
  226.     return 0;
  227. }
  228.  
  229. long m_creat(dir,name,mode,attr,entry)
  230. fcookie *dir;
  231. char *name;
  232. unsigned mode;
  233. int attr;
  234. fcookie *entry;
  235. {
  236.     long pos;
  237.     d_inode ripnew;
  238.     unshort newfile;
  239.     char *ext;
  240.     
  241.     /* Create dir entry */    
  242.     if((pos=search_dir(name,dir->index,dir->dev,ADD))<0)
  243.     {    
  244.         return pos;
  245.     }
  246.  
  247.     /* Get new inode */
  248.     if(!(newfile=alloc_inode(dir->dev)))
  249.     {
  250.         DEBUG("m_getdev: no free inodes");
  251.         return EWRITF;
  252.     }
  253.     /* Set up inode */
  254.     bzero(&ripnew,sizeof(d_inode));
  255.  
  256. /* If  creating a file with approriate extensions 
  257.  * automatically give it execute permissions.
  258.  */
  259.     if(do_trans(AEXEC_TOS,dir->dev) && ( ext=strrchr(name,'.') ) )
  260.     {
  261.         ext++;
  262.         if( 
  263.         /* Insert your favourite extensions here */
  264.           !(  Stricmp(ext,"TTP") && Stricmp(ext,"PRG") 
  265.            && Stricmp(ext,"APP") && Stricmp(ext,"TOS") 
  266.            && Stricmp(ext,"ACC") && Stricmp(ext, "GTP")))
  267.                 mode |= 0111;
  268.     }
  269.     ripnew.i_mode= I_REGULAR | mode;
  270.     ripnew.i_uid=Getuid();
  271.     ripnew.i_gid=Getgid();
  272.     ripnew.i_nlinks=1;
  273.  
  274.     ripnew.i_mtime=Unixtime(Timestamp(), Datestamp());
  275.     ripnew.i_atime=ripnew.i_mtime;
  276.     ripnew.i_ctime=ripnew.i_mtime;
  277.  
  278.     write_inode(newfile,&ripnew,dir->dev);
  279.     l_write(dir->index,pos,2L,&newfile,dir->dev);
  280.  
  281.     if(cache_mode) l_sync();
  282.  
  283.     entry->fs = dir->fs;
  284.     entry->dev = dir->dev;
  285.     entry->index=newfile;
  286.     entry->aux=0;
  287.     return 0;
  288. }
  289.  
  290. DEVDRV * m_getdev(file,special)
  291. fcookie *file;
  292. long *special;
  293. {
  294.     return(&minix_dev);
  295. }
  296.  
  297. long m_getxattr(file,xattr)
  298. fcookie *file;
  299. XATTR *xattr;
  300. {
  301.         d_inode rip;
  302.     long time_tmp;
  303.     super_info *psblk;
  304.     psblk=super_ptr[file->dev];
  305.     read_inode(file->index,&rip,file->dev);
  306.     /* Minix and gcc use different values for FIFO's */
  307.     if((rip.i_mode & I_TYPE) == I_NAMED_PIPE)
  308.         xattr->mode = S_IFIFO | (rip.i_mode & ALL_MODES);
  309.     else xattr->mode=rip.i_mode;
  310.  
  311.     /* We could potentially have trouble with symlinks too */
  312. #if I_SYMLINK != S_IFLNK
  313.     if( (rip.i_mode & I_TYPE) == I_SYMLINK)
  314.         xattr->mode = S_IFLNK | (rip.i_mode & ALL_MODES);
  315. #endif
  316.  
  317.     /* Fake attr field a bit , to keep TOS happy */
  318.     if(IS_DIR(rip))xattr->attr=FA_DIR;
  319.     else xattr->attr=(rip.i_mode & 0222) ? 0 : FA_RDONLY;
  320.  
  321.         xattr->index=file->index;
  322.         xattr->dev=file->dev;
  323.  
  324.     /* Char and block special files need major/minor device nos filled in */
  325.     if(IM_SPEC(rip.i_mode)) xattr->rdev=rip.i_zone[0];
  326.         else xattr->rdev=0;
  327.  
  328.         xattr->nlink=rip.i_nlinks;
  329.         xattr->uid=rip.i_uid;
  330.         xattr->gid=rip.i_gid;
  331.         xattr->size=rip.i_size;
  332.     xattr->blksize = BLOCK_SIZE;
  333. /* Note: the nblocks calculation is accurate only if the file is
  334.  * contiguous. It usually will be, and if it's not, it shouldn't
  335.  * matter ('du' will return values that are slightly too high)
  336.  */
  337.     xattr->nblocks = (xattr->size + (BLOCK_SIZE-1)) / BLOCK_SIZE;
  338.     if (xattr->nblocks >= psblk->dzpi)
  339.         xattr->nblocks++;    /* correct for the indirection block */
  340.     if (xattr->nblocks > psblk->ndbl) {
  341.         xattr->nblocks++;    /* correct for double indirection block */
  342.         xattr->nblocks += ((xattr->nblocks-(psblk->ndbl+2))/psblk->zpind);
  343.                 /* and single indirection blocks */
  344.     }
  345.  
  346.     time_tmp=Dostime(_corr(rip.i_mtime));
  347.     xattr->mtime=time_tmp >> 16;
  348.     xattr->mdate=time_tmp & (0xffff);
  349.     time_tmp=Dostime(_corr(rip.i_atime));
  350.     xattr->atime=time_tmp >> 16;
  351.     xattr->adate=time_tmp & (0xffff);
  352.     time_tmp=Dostime(_corr(rip.i_ctime));
  353.     xattr->ctime=time_tmp >> 16;
  354.     xattr->cdate=time_tmp & (0xffff);
  355.  
  356.     xattr->reserved2=0;
  357.     xattr->reserved3[0]=0;
  358.     xattr->reserved3[1]=0;
  359.  
  360.     return 0;
  361. }
  362.  
  363. long m_chown(file, uid , gid)
  364. fcookie *file;
  365. int uid,gid;
  366. {
  367.  
  368.     d_inode rip;
  369.     read_inode(file->index,&rip,file->dev);
  370.      if(uid!=-1)rip.i_uid=uid;
  371.     if(gid!=-1)rip.i_gid=gid;
  372.     rip.i_ctime=Unixtime(Timestamp(),Datestamp());
  373.     write_inode(file->index,&rip,file->dev);
  374.     if(cache_mode) l_sync();
  375.     return 0;
  376. }
  377.  
  378. long m_chmode(file, mode)
  379. fcookie *file;
  380. unsigned mode;
  381. {
  382.         d_inode rip;
  383.     super_info *psblk=super_ptr[file->dev];
  384.  
  385.         read_inode(file->index,&rip,file->dev);
  386.  
  387.         rip.i_mode=(rip.i_mode & I_TYPE)|(mode & ALL_MODES);                
  388.     if(psblk->version)rip.i_ctime=Unixtime(Timestamp(),Datestamp());
  389.     write_inode(file->index,&rip,file->dev);
  390.     if(cache_mode) l_sync();
  391.         return 0;
  392. }
  393.  
  394.  
  395. long m_mkdir(dir,name,mode)
  396. fcookie *dir;
  397. char *name;
  398. unsigned mode;
  399. {
  400.     unshort newdir;
  401.     d_inode rip,ripnew;
  402.     long pos;
  403.     int incr;
  404.     dir_struct blank[MAX_INCREMENT*2];
  405.     incr=super_ptr[dir->dev]->increment;
  406.     if((pos=search_dir(name,dir->index,dir->dev,ADD))<0)return pos;
  407.     read_inode(dir->index,&rip,dir->dev);
  408.     if(rip.i_nlinks>=MINIX_MAX_LINK)return EACCDN;
  409.     /* Get new inode */
  410.     if(!(newdir=alloc_inode(dir->dev)))return EACCDN;
  411.  
  412.     /* Set up inode */
  413.     bzero(&ripnew,sizeof(d_inode));
  414.     ripnew.i_mode=I_DIRECTORY | (mode & 0777);
  415.     ripnew.i_uid=Getuid();
  416.     ripnew.i_gid=Getgid();
  417.     ripnew.i_nlinks=2;
  418.     ripnew.i_mtime=Unixtime(Timestamp(), Datestamp());
  419.     ripnew.i_ctime=ripnew.i_mtime;
  420.     ripnew.i_atime=ripnew.i_mtime;
  421.     write_inode(newdir,&ripnew,dir->dev);
  422.  
  423.     /* Set up new directory */
  424.     strcpy(blank[0].d_name,".");
  425.     blank[0].d_inum=newdir;
  426.     strcpy(blank[incr].d_name,"..");
  427.     blank[incr].d_inum=dir->index;
  428.     if(l_write((unsigned)newdir,-1L,(long)(DIR_ENTRY_SIZE*2*incr),
  429.         blank,dir->dev)!=(incr*DIR_ENTRY_SIZE*2) )
  430.     {
  431.         ripnew.i_mode=0;
  432.         ripnew.i_nlinks=0;
  433.         write_inode(newdir,&ripnew,dir->dev);
  434.         free_inode(newdir,dir->dev);
  435.         if(cache_mode) l_sync();
  436.         return EACCDN;
  437.     }
  438.     rip.i_nlinks++;
  439.     write_inode(dir->index,&rip,dir->dev);
  440.     l_write(dir->index,pos,2L,&newdir,dir->dev);
  441.  
  442.     if(cache_mode) l_sync();
  443.  
  444.     return(0);
  445. }
  446.  
  447. long m_rmdir(dir,name)
  448. fcookie *dir;
  449. char *name;
  450. {
  451.     long chunk,left;
  452.     long inum;
  453.     int i,incr;
  454.     super_info *psblk;
  455.     d_inode rip,rip2;
  456.     if((inum=search_dir(name,dir->index,dir->dev,FIND))<0)return inum;
  457.  
  458.     /* Is anything mounted on this dir ? */
  459.     for(psblk=super_ptr[dir->dev]->mnt_first;psblk;psblk=psblk->mnt_next)
  460.         if(psblk->mnt_inode==inum)
  461.         {
  462.             DEBUG("m_rmdir: can't delete mount point");
  463.             return EACCDN;
  464.         }
  465.  
  466.     read_inode(inum,&rip,dir->dev);
  467.     read_inode(dir->index,&rip2,dir->dev);
  468.     if(!IS_DIR(rip))return EFILNF;
  469.     incr=super_ptr[dir->dev]->increment;
  470.     /* Check if dir is actually empty */
  471.     for(chunk=0;(left=next_zone(&rip,chunk,&temp,dir->dev)/DIR_ENTRY_SIZE);
  472.         chunk++)
  473.     {
  474.         for(i=0;i<left;i+=incr)
  475.            if (temp.bdir[i].d_inum
  476.                && (temp.bdir[i].d_name[0] != '.'
  477.                || temp.bdir[i].d_name[1] != 0)
  478.                && (temp.bdir[i].d_name[0] != '.'
  479.                || temp.bdir[i].d_name[1] != '.'
  480.                || temp.bdir[i].d_name[2] != 0))
  481.             return EACCDN ;
  482.     }
  483.     if(!inode_busy(inum,dir->dev,1))
  484.     {
  485.         trunc_inode(&rip,dir->dev,0L,0);
  486.         rip.i_mode=0;
  487.         free_inode(inum,dir->dev);
  488.     }
  489.     rip.i_nlinks=0;
  490.     write_inode(inum,&rip,dir->dev);
  491.     read_inode(dir->index,&rip,dir->dev);
  492.     rip.i_mtime=Unixtime(Timestamp(), Datestamp());
  493.     rip.i_nlinks--;
  494.     write_inode(dir->index,&rip,dir->dev);
  495.     search_dir(name,dir->index,dir->dev,KILL);
  496.  
  497.     if( lpath && (ldir.dev==dir->dev) && (ldir.index==inum) )
  498.     {
  499.         Kfree(lpath);
  500.         lpath=0;
  501.     }
  502.  
  503.     if(cache_mode) l_sync();
  504.  
  505.     return(0);
  506. }
  507.  
  508. /* Unix-like unlink ... handle regulars, symlinks and specials.
  509.  * 
  510.  */
  511.  
  512. long m_remove(dir,name)
  513. fcookie *dir;
  514. char *name;
  515. {
  516.     long inum,ret;
  517.     char spec;    /* Special file */
  518.     d_inode rip;
  519.     inum=search_dir(name,dir->index,dir->dev,FIND);
  520.     if(inum<0) return inum;
  521.     read_inode(inum,&rip,dir->dev);
  522.     if(!IS_REG(rip) && !IS_SYM(rip) ) 
  523.     {
  524.         if(!IM_SPEC(rip.i_mode)) return EACCDN;
  525.         spec=1;
  526.     }
  527.     else spec=0;
  528.     if((ret=search_dir(name,dir->index,dir->dev,KILL))<0) return ret;    
  529.     if(--rip.i_nlinks==0)
  530.     {
  531.         if(spec || !inode_busy(inum,dir->dev,1)) /* Is inode busy ? */
  532.         {
  533.             if(!spec) trunc_inode(&rip,dir->dev,0L,0);
  534.             rip.i_mode=0;
  535.             free_inode(inum,dir->dev);
  536.         }
  537.     }
  538.     write_inode(inum,&rip,dir->dev);
  539.  
  540.     if(cache_mode) l_sync();
  541.  
  542.     return(0);
  543. }
  544.  
  545. /* This function is inefficient, it uses the standard sys V method of 
  546.  * finding out the pathname of the cwd : for each part of the path, search
  547.  * the parent for a link with the same inode number as '..' , append this to the
  548.  * path until we get to root dir, then reverse order of dirs. This way no 
  549.  * temporary buffers are allocated which could overflow or kmalloc to fail ...
  550.  */
  551.  
  552. /* In fact its so inefficient a mini-cache remembers the last call info */
  553.  
  554. long m_getname(root,dir,pathname,length)
  555. fcookie *root,*dir;
  556. char *pathname;
  557. short length;
  558. {
  559.     long inum,pinum;
  560.     unsigned dev;
  561.     int chunk;
  562.     long left;
  563.     int incr;
  564.     short plength;
  565.     super_info *psblk;
  566.     psblk=super_ptr[dir->dev];
  567.  
  568.     if(no_length) length=PATH_MAX;
  569.  
  570.     if(lpath && lroot.dev==root->dev && 
  571.         lroot.index==root->index && ldir.dev==dir->dev && 
  572.         ldir.index==dir->index)
  573.     {
  574.         TRACE("m_getname: cache hit");
  575.         if(length <= llength) return ENAMETOOLONG;
  576.         strcpy(pathname,lpath);
  577.         return 0;
  578.     }
  579.  
  580.     *pathname=0;
  581.  
  582.     if( dir->dev==root->dev && dir->index==root->index) return 0;
  583.  
  584.     incr=psblk->increment;
  585.     inum=dir->index;
  586.     dev=dir->dev;
  587.     plength=0;
  588.     if(inum==ROOT_INODE && psblk->mnt_inode)
  589.     {
  590.         dev=psblk->mnt_dev;
  591.         inum=psblk->mnt_inode;
  592.         psblk=super_ptr[dev];
  593.     }
  594.  
  595.     while( inum!=root->index && inum!= ROOT_INODE )
  596.     {
  597.         d_inode rip;
  598.         cache *tmp;
  599.         pinum=search_dir("..",inum,dev,FIND); 
  600.         /* Parent inum */
  601.  
  602.         if(pinum < 0) /* If this happens we're in trouble */
  603.         {
  604.             ALERT("No .. in inode %d , drive %c",inum,dir->dev+'A');
  605.             return pinum;
  606.         }
  607.         read_inode(pinum,&rip,dev);
  608.         for(chunk=0;
  609.         (left=cnext_zone(&rip,chunk,&tmp,dev)/DIR_ENTRY_SIZE) &&
  610.         inum!=pinum ;chunk++)
  611.         {
  612.             char tname[MNAME_MAX+1];
  613.             int i;
  614.             for(i=0;i<left && inum!=pinum ;i+=incr)
  615.             if(tmp->buffer->bdir[i].d_inum==inum)
  616.             {
  617.                 strncpy(tname,tmp->buffer->bdir[i].d_name,MMAX_FNAME(incr));
  618.                 tname[MMAX_FNAME(incr)]=0;
  619.                 strrev(tname);
  620.                 plength+=strlen(tname)+1;
  621.                 if(length <= plength) return ENAMETOOLONG;
  622.                 strcat(pathname,tname);
  623.                 strcat(pathname,"\\");
  624.                 inum=pinum;
  625.             }
  626.         }
  627.         if(left==0 && inum!=pinum) {
  628.             ALERT("m_getname inode %d orphaned or bad ..",inum);
  629.             return EINTRN;
  630.         }
  631.         /* Cross mount point if possible */
  632.         if(inum==ROOT_INODE && psblk->mnt_inode)
  633.         {
  634.             dev=psblk->mnt_dev;
  635.             inum=psblk->mnt_inode;
  636.             psblk=super_ptr[dev];
  637.         }
  638.     }
  639.     if(inum==ROOT_INODE && root->index!=ROOT_INODE)
  640.     {
  641.         DEBUG("m_getname: Hmmmm root is not a parent of dir");
  642.         return EINTRN;
  643.     }
  644.     strrev(pathname);
  645.     if(lpath)Kfree(lpath);
  646.     if( (lpath=Kmalloc(strlen(pathname)+1)) )
  647.     {
  648.         strcpy(lpath,pathname);
  649.         llength=plength;
  650.     }
  651.  
  652.     lroot=*root;
  653.     ldir=*dir;
  654.     return 0;
  655. }
  656.  
  657.  
  658. long m_opendir(dirh,flag)
  659. DIR *dirh;
  660. int flag;
  661. {
  662.     dirh->index=0;
  663.     return 0;
  664. }
  665.  
  666. long m_readdir(dirh,name,namelen,fc)
  667. DIR *dirh;
  668. char *name;
  669. int namelen;
  670. fcookie *fc;
  671. {
  672.         d_inode rip;
  673.     cache *tmp;
  674.     unsigned entry,chunk;
  675.     super_info *psblk;
  676.     long limit;
  677.     int flag,incr;
  678.     psblk=super_ptr[dirh->fc.dev];
  679.     if(dirh->flags) flag=do_trans(DIR_TOS,dirh->fc.dev);
  680.     else flag=0;
  681.     if(!dirh->fc.index)return EACCDN;
  682.     entry=dirh->index % NR_DIR_ENTRIES;
  683.     chunk=dirh->index / NR_DIR_ENTRIES;    
  684.     read_inode(dirh->fc.index,&rip,dirh->fc.dev);
  685.     incr=psblk->increment;
  686.  
  687.     while( (limit=cnext_zone(&rip,chunk,&tmp,dirh->fc.dev)/DIR_ENTRY_SIZE) )
  688.     {
  689.         while( entry < limit)
  690.           {
  691.             dir_struct *try=&tmp->buffer->bdir[entry];
  692.             entry+=incr;
  693.             if(try->d_inum)
  694.             {
  695.                 char *tmpnam;
  696.                 tmpnam=tosify(try->d_name,flag,MMAX_FNAME(incr));
  697.  
  698.                 if (dirh->flags==0)
  699.                 {
  700.                     namelen -= sizeof(long);
  701.                     if (namelen <= 0) return ERANGE;
  702.                     *((long *)name) = (long)try->d_inum;
  703.                     name += sizeof(long);
  704.                        }
  705.  
  706.                 strncpy(name,tmpnam,namelen);
  707.                 dirh->index=entry+chunk*NR_DIR_ENTRIES;
  708.             /* set up a file cookie for this entry */
  709.                 fc->dev = dirh->fc.dev;
  710.                 fc->aux = 0;
  711.                 fc->index = (long)try->d_inum;
  712.                 fc->fs = &minix_filesys;
  713.                 if(strlen(tmpnam) >= namelen) 
  714.                     return ENAMETOOLONG;
  715.                 /* If turbo mode set atime here: we'll only
  716.                  * change the cache here so it wont cause
  717.                  * lots of I/O
  718.                  */
  719.                 if( cache_mode==TURBO
  720.                     && super_ptr[dirh->fc.dev]->version
  721.                     && dirh->fc.dev > 1 )
  722.                                set_atime(&dirh->fc);
  723.                 return 0;
  724.             }
  725.         }
  726.         if(entry!=NR_DIR_ENTRIES)return ENMFIL;
  727.         else entry=0;
  728.         chunk++;
  729.     }
  730.     return ENMFIL;
  731. }
  732.  
  733. long m_rewinddir(dirh)
  734. DIR *dirh;
  735. {
  736.     dirh->index=0;
  737.     return 0;
  738. }
  739.  
  740. long m_closedir(dirh)
  741. DIR *dirh;
  742. {
  743.  
  744. /* Access time is set here if we aren't in TURBO cache mode. Otherwise we
  745.  * would be sync'ing on every dir read which would be far too slow. See note
  746.  * in set_atime().
  747.  */
  748.  
  749.     if( cache_mode!=TURBO && super_ptr[dirh->fc.dev]->version && 
  750.             dirh->fc.dev > 1 )
  751.     {
  752.         set_atime(&dirh->fc);
  753.         l_sync();
  754.     }
  755.  
  756.     dirh->fc.index=0;
  757.     return 0;
  758. }
  759.  
  760. /* Set the atime of a V2 inode for filesystems. There is a snag here: if the
  761.  * disk is changed then this is likely not to be written out before the whole
  762.  * cache is invalidated. So we set the status to '3' which means that it is
  763.  * not alerted if this is dirty when invalidated (hardly the end of the world
  764.  * if the atime is slightly wrong!)
  765.  */
  766. void set_atime(fc)
  767. fcookie *fc;
  768. {
  769.     d_inode *rip;
  770.     int *status;
  771.     rip=get_inode2(fc->index,fc->dev,&status,NOGUESS);
  772.     rip->i_atime=Unixtime(Timestamp(),Datestamp());
  773.     if(*status!=2) *status=3;
  774. }
  775.  
  776.  
  777. long m_rlabel(dir,name,namelen)
  778. fcookie *dir;
  779. char *name;
  780. int namelen;
  781. {
  782.     return EFILNF;
  783. }
  784.  
  785. long m_wlabel(dir,name)
  786. fcookie *dir;
  787. char *name;
  788. {
  789.     return EACCDN;
  790. }
  791.  
  792. long m_dfree(dir,buffer)
  793. fcookie *dir;
  794. long *buffer;
  795. {
  796.     super_info *psblk ;
  797.     psblk = super_ptr[dir->dev];
  798.     buffer[1] = psblk->sblk.s_zones-psblk->sblk.s_firstdatazn;
  799.     buffer[0] = buffer[1] - count_bits(psblk->zbitmap,buffer[1]+1)+1;
  800.     buffer[2]=512L;
  801.     buffer[3]=2L;
  802.     return(0);
  803. }
  804.  
  805. long m_fscntl(dir,name,cmd,arg)
  806. fcookie *dir;
  807. char *name;
  808. int cmd;
  809. long arg;
  810. {
  811.     FILEPTR *f;
  812.     mfs_info *inf;
  813.     super_info *psblk;
  814.     long inum;
  815.     int uid,gid,id;
  816.     d_inode rip;
  817.     extern long init_addr;
  818.  
  819.     uid = Geteuid();
  820.     gid = Getegid();
  821.  
  822.     switch(cmd)
  823.     {
  824.         case MFS_VERIFY:
  825.         *((long *)arg)=MFS_MAGIC;
  826.         return 0;
  827.  
  828.         /* Sync the filesystem */
  829.         case MFS_SYNC:
  830.         TRACE("Done l_sync()");
  831.         l_sync();
  832.         return 0;
  833.  
  834.         /* Invalidate all cache entries for a given drive */
  835.         case MFS_CINVALID:
  836.         if(uid) return EACCDN;
  837.         m_invalidate(dir->dev);
  838.         return 0;
  839.  
  840.         /* Invalidate all fileptrs for a given drive */
  841.         case MFS_FINVALID:
  842.         if(uid) return EACCDN;
  843.         id=Getpid();
  844.         for(f=firstptr;f;f=f->next)if(f->fc.dev==dir->dev)m_close(f,id);
  845.         return 0;
  846.  
  847.         case MFS_INFO:
  848.         psblk=super_ptr[dir->dev];
  849.         inf=(mfs_info *)arg;
  850.         inf->total_zones=psblk->sblk.s_zones-psblk->sblk.s_firstdatazn;
  851.         inf->total_inodes=psblk->sblk.s_ninodes;
  852.         inf->version=psblk->version+1;
  853.         inf->increment=psblk->increment;        
  854.         inf->free_inodes=inf->total_inodes-
  855.             count_bits(psblk->ibitmap,inf->total_inodes+1)+1;
  856.         inf->free_zones=inf->total_zones-count_bits(psblk->zbitmap,inf->total_zones+1)+1;
  857.         return 0;
  858.  
  859.         case MFS_IMODE:
  860.         if(uid) return EACCDN;
  861.         inum=search_dir(name,dir->index,dir->dev,FIND);
  862.         if(inum < 0 ) return inum;
  863.         read_inode(inum,&rip,dir->dev);
  864.         rip.i_mode=arg;
  865.         write_inode(inum,&rip,dir->dev);
  866.         return 0;
  867.  
  868.         case MFS_GTRANS:
  869.         *((long *) arg)=fs_mode[dir->dev];
  870.         return 0;
  871.  
  872.         case MFS_STRANS:
  873.         if(uid) return EACCDN;
  874.         fs_mode[dir->dev]=*((long *)arg);
  875.         return 0;
  876.  
  877.         case MFS_PHYS:
  878.         *((struct phys_part *)arg)=ppart[dir->dev];
  879.         return 0;
  880.  
  881.         case MFS_IADDR:
  882.         *((long *)arg)=(long)&init_addr;
  883.         return 0;
  884.  
  885.         case MFS_UPDATE:
  886.         if(cache_mode!=TURBO ) return -1;
  887.         switch(arg)
  888.         {
  889.             case 0:
  890.             return update_suspend;
  891.  
  892.             case 1:
  893.             TRACE("Minixfs: update suspended");
  894.             update_suspend=1;
  895.             return 0;
  896.  
  897.             case 2:
  898.             TRACE("Minixfs: update restarted");
  899.             update_suspend=0;
  900.             return 0;
  901.  
  902.             case 3:
  903.             if(Addroottimeout) return -1;
  904.             return update_pid;
  905.  
  906.             default:
  907.             return EINVFN;
  908.         }
  909.  
  910. /* Mounting and umounting.
  911.  * This basically involves cookie translation when crossing the mount point.
  912.  * However this presents an interesting problem. Suppose E:\usr has D: mounted
  913.  * on it. If we are in directory E:\usr\ we are in the root directory of D:.
  914.  * If we do a cd \ then we get sent back to the root cookie directory of D:,
  915.  * which we want to be E:. The only way to change the root cookie at present is
  916.  * to force a disk change, this is no problem.
  917.  * The fun starts when we want to umount D:. Changing D: will have no effect
  918.  * because the root cookie of D: is now on E: and since E: hasn't changed the
  919.  * root cookie on D: wont change either. If we change E: then we will get the
  920.  * root cookie of D: changed but we also change E: as well.
  921.  * The only way out is to fiddle the aux field of the root cookie so it shows
  922.  * the original device. The cookie from m_root is copied with the dup_cookie
  923.  * function, if we kludge this at umount time to read the aux field and copy
  924.  * the original device the root cookies should be set back. This relies very
  925.  * heavily on the structure of filesys.c in MiNT, but it's better than nothing.
  926.  * Repeat after me: KLUDGE, KLUDGE, KLUDGE, KLUDGE, KLUDGE!!!
  927.  */
  928.  
  929.         case MFS_MOUNT:
  930.         {
  931.             char tpath[]="A:";
  932.             fcookie fc;
  933.             unsigned dev;
  934.             super_info *mptr;
  935.             if(uid) return EACCDN;
  936.             /* Lookup the entry */
  937.             if( (inum=m_lookup(dir,name,&fc)) ) return inum;
  938.             read_inode(fc.index,&rip,fc.dev);
  939.             /* Must be a directory */
  940.             if(!IS_DIR(rip))
  941.             {
  942.                 DEBUG("MFS_MOUNT: not a directory!");
  943.                 return EACCDN;
  944.             }
  945.  
  946.             if(fc.index==ROOT_INODE)
  947.             {
  948.                 DEBUG("MFS_MOUNT: can't mount on root!");
  949.                 return EACCDN;
  950.             }
  951.             if(!arg) return EINVFN;
  952.             dev = ( ( mfs_mount *) arg)->dev ;
  953.  
  954.             if(fc.dev==dev)
  955.             {
  956.                 DEBUG("MFS_MOUNT: can't mount on self!");
  957.                 return EACCDN;
  958.             }
  959.  
  960.             tpath[0]='A'+dev;
  961.  
  962.             /* Sync filesystem (and force access if unrecognised) */
  963.  
  964.             d_cntl(MFS_SYNC,tpath,0l);
  965.  
  966.             psblk=super_ptr[dev];
  967.  
  968.             if(!psblk || psblk==DFS)
  969.             {
  970.                 DEBUG("MFS_MOUNT: not a Minixfs filesystem!");
  971.                 return EACCDN;
  972.             }
  973.  
  974.             if(psblk->mnt_inode)
  975.             {
  976.               DEBUG("MFS_MOUNT: filesystem already mounted!");
  977.               return EACCDN;
  978.             }
  979.  
  980.             if(psblk->mnt_first)
  981.             {
  982.               DEBUG("MFS_MOUNT: filesystem has others mounted!");
  983.               return EACCDN;
  984.             }
  985.  
  986.             for(mptr=super_ptr[fc.dev]->mnt_first;
  987.                           mptr;mptr=mptr->mnt_next)
  988.             {
  989.               if( mptr->mnt_inode==fc.index )
  990.               {
  991.                 DEBUG("MFS_MOUNT: inode already mounted on!");
  992.                 return EACCDN;
  993.               }
  994.             }
  995.  
  996.             mptr=super_ptr[fc.dev];
  997.  
  998.             psblk->mnt_next=mptr->mnt_first;
  999.             mptr->mnt_first=psblk;
  1000.  
  1001.             psblk->mnt_dev=fc.dev;
  1002.             psblk->mnt_inode=fc.index;
  1003.  
  1004.             psblk->mnt_flags |= MNT_CHANGE;
  1005.  
  1006.             /* Force change */
  1007.             d_lock(1,dev);
  1008.             d_lock(0,dev);
  1009.  
  1010.             d_cntl(MFS_SYNC,tpath,0l);
  1011.  
  1012.             psblk->mnt_flags &= ~MNT_CHANGE;
  1013.  
  1014.             return 0;
  1015.         }
  1016.  
  1017.         case MFS_UMOUNT:
  1018.         {
  1019.             fcookie fc;
  1020.             super_info **pptr,*pdev;
  1021.             char tpath[]="A:";
  1022.  
  1023.             if(uid) return EACCDN;
  1024.             /* Lookup path */
  1025.             if( ( inum=m_lookup(dir,name,&fc) ) ) return inum;
  1026.  
  1027.             psblk=super_ptr[fc.dev];
  1028.  
  1029.             /* Can't have other devices mounted */
  1030.             if(psblk->mnt_first)
  1031.             {
  1032.                 DEBUG("MFS_UMOUNT: device busy");
  1033.                 return EACCDN;
  1034.             }
  1035.  
  1036.             if(!psblk->mnt_inode)
  1037.             {
  1038.                 DEBUG("MFS_UMOUNT: not mounted");
  1039.                 return EACCDN;
  1040.             }
  1041.  
  1042.             /* Unlink from parent filesystem list */
  1043.             for(pptr=&super_ptr[psblk->mnt_dev]->mnt_first;*pptr;
  1044.                               pptr=&(*pptr)->mnt_next )
  1045.             {
  1046.                 if(*pptr==psblk)
  1047.                 {
  1048.                     *pptr = psblk->mnt_next;
  1049.                     break;
  1050.                 }
  1051.             }
  1052.  
  1053.             pdev=psblk;
  1054.  
  1055.             /* Find root device */
  1056.             while(pdev->mnt_inode) pdev = super_ptr[pdev->mnt_dev];
  1057.  
  1058.             psblk->mnt_inode=0;
  1059.  
  1060.             pdev->mnt_flags |= MNT_CHANGE;
  1061.  
  1062.             /* Make dupcookie restore dev fields */
  1063.             restore_dev = psblk->dev;
  1064.  
  1065.             /* Change root device */
  1066.             d_lock(1,pdev->dev);
  1067.             d_lock(0,pdev->dev);
  1068.  
  1069.             tpath[0] = 'A'+pdev->dev;
  1070.             d_cntl(MFS_SYNC,tpath,0l);
  1071.  
  1072.             restore_dev = -1;
  1073.  
  1074.             pdev->mnt_flags &= ~MNT_CHANGE;
  1075.  
  1076.             return 0;
  1077.  
  1078.         }
  1079.  
  1080.         case FUTIME:
  1081.         case FTRUNCATE:
  1082.         {
  1083.             fcookie fc;
  1084.             read_inode(dir->index,&rip,dir->dev);
  1085.         /* Have we got 'x' access for current dir ? */
  1086.          if (check_mode(uid,gid,&rip,S_IXUSR)) 
  1087.           return EACCDN;
  1088.         /* Lookup the entry */
  1089.             if( (inum=m_lookup(dir,name,&fc)) ) return inum;
  1090.             read_inode(fc.index,&rip,fc.dev);
  1091.             if(cmd==FUTIME)
  1092.             {
  1093.                 short *timeptr = (short *) arg;
  1094.               /* The owner or super-user can always touch,
  1095.                  others only if timeptr == 0 and write
  1096.                  permission. */
  1097.               if (uid && uid != rip.i_uid
  1098.                   && (timeptr
  1099.                   || check_mode (uid, gid, &rip, S_IWUSR)))
  1100.                 return EACCDN;
  1101.                 
  1102.               rip.i_ctime = Unixtime(Timestamp (), Datestamp ());
  1103.               if(timeptr)
  1104.               {    
  1105.                 rip.i_atime = Unixtime(timeptr[0], timeptr[1]);
  1106.                 rip.i_mtime = Unixtime(timeptr[2], timeptr[3]);
  1107.               }
  1108.               else rip.i_atime = rip.i_mtime = rip.i_ctime;
  1109.                 write_inode (fc.index, &rip, fc.dev);
  1110.                 if (cache_mode != TURBO) l_sync();
  1111.                 return 0;
  1112.             }
  1113.  
  1114.             if(!IS_REG(rip)) return EACCDN;
  1115.             /* Need write access as well */
  1116.             if (check_mode(uid, gid, &rip, S_IWUSR))
  1117.               return EACCDN;
  1118.             itruncate(fc.index,fc.dev,*((long *)arg));
  1119.               if (cache_mode != TURBO) l_sync ();
  1120.             return 0;
  1121.         }
  1122.  
  1123.         case MFS_LOPEN:
  1124.         {
  1125.           long fcount;
  1126.           openf_list *flist = (openf_list *) arg;
  1127.           fcount=0;
  1128.           inum=0;
  1129.           for(f=firstptr;f;f=f->next)
  1130.           {
  1131.             /* If same file or wrong device, skip */
  1132.             if( f->fc.dev!=dir->dev || f->fc.index==inum) continue;
  1133.             inum=f->fc.index;
  1134.             flist->flist[fcount++]=inum;
  1135.             if(fcount==flist->limit) return ERANGE;
  1136.           }
  1137.           flist->flist[fcount]=0;
  1138.         }
  1139.         return 0;
  1140.  
  1141.         case MFS_MKNOD:
  1142.         {
  1143.              long pos;
  1144.             unsigned inm,mode;
  1145.  
  1146.              if(uid) return EACCDN;
  1147.              mode = arg & 0xffff;
  1148.  
  1149.              /* Char and block specials only at present */
  1150.              if(!IM_SPEC(mode))return ERANGE;
  1151.  
  1152.              /* Create new name */
  1153.              pos=search_dir(name,dir->index,dir->dev,ADD);
  1154.              if(pos < 0) return pos;         
  1155.              inm=alloc_inode(dir->dev);
  1156.              if(!inm) return EWRITF;
  1157.  
  1158.              bzero(&rip,sizeof(d_inode));
  1159.  
  1160.             rip.i_mode = mode;
  1161.             rip.i_uid = uid;
  1162.             rip.i_gid = gid;
  1163.             rip.i_nlinks = 1;
  1164.  
  1165.             rip.i_mtime=Unixtime(Timestamp(), Datestamp());
  1166.             rip.i_atime=rip.i_mtime;
  1167.             rip.i_ctime=rip.i_mtime;
  1168.             rip.i_zone[0]= arg >> 16;
  1169.  
  1170.             write_inode(inm,&rip,dir->dev);
  1171.             l_write(dir->index,pos,2L,&inm,dir->dev);
  1172.             if(cache_mode) l_sync();
  1173.  
  1174.         }
  1175.         return 0;
  1176.  
  1177.         default:
  1178.         return EINVFN;
  1179.     }
  1180. }
  1181.  
  1182. /* m_rename, move a file or directory. Directories need special attention 
  1183.  * because if /usr/foo is moved to /usr/foo/bar then the filesystem will be
  1184.  * damaged by making the /usr/foo directory inaccessible. The sanity checking
  1185.  * performed is very simple but should cover all cases: Start at the parent
  1186.  * of the destination , check if this is the source inode , if not then 
  1187.  * move back to '..' and check again , repeatedly check until the root inode
  1188.  * is reached , if the source is ever seen on the way back to the root then
  1189.  * the rename is invalid , otherwise it should be OK.
  1190.  */
  1191.  
  1192. long m_rename(olddir,oldname,newdir,newname)
  1193. fcookie *olddir;
  1194. char *oldname;
  1195. fcookie *newdir;
  1196. char *newname;
  1197. {
  1198.     long finode,ret;
  1199.     d_inode rip;
  1200.     long pos;
  1201.     char dirmove,dirren;
  1202.     dirmove=0;
  1203.     dirren=0;
  1204. /* Check cross drives */
  1205.     if(olddir->dev!=newdir->dev)return EXDEV;
  1206.  
  1207. /* Check new doesn't exist and path is otherwise valid */
  1208.     finode=search_dir(newname,newdir->index,newdir->dev,FIND);
  1209.     if(finode>0) return EACCDN;
  1210.     if(finode!=EFILNF) return finode;
  1211.  
  1212. /* Check old path OK */
  1213.     if((finode=search_dir(oldname,olddir->index,olddir->dev,FIND))<0)
  1214.         return finode;
  1215.  
  1216.     read_inode(finode,&rip,olddir->dev);
  1217.  
  1218. /* Sanity check movement of directories */
  1219.     if(IS_DIR(rip))
  1220.     {
  1221.         dirren=1;
  1222.          if(olddir->index!=newdir->index)
  1223.         {
  1224. #ifdef MFS_NMOVE_DIR
  1225.             return EACCDN;
  1226. #else
  1227.             d_inode riptemp;
  1228.             ret=is_parent(newdir->index,finode,olddir->dev);
  1229.             if(ret < 0) return ret;
  1230.             if(ret) return EACCDN;
  1231.             read_inode(newdir->index,&riptemp,newdir->dev);
  1232.             if(riptemp.i_nlinks==MINIX_MAX_LINK) return EACCDN;
  1233.             TRACE("minixfs: valid directory move");
  1234.             dirmove=1;
  1235. #endif
  1236.         }
  1237.     }
  1238.  
  1239.     /* Check the m_getname cache is not invalidated by this move ....
  1240.     if no dir move, invalidate if the ldir is the name being changed ,
  1241.     if we move dir's then if the olddir is a parent of ldir, invalidate */
  1242.  
  1243.     if (lpath && ldir.dev == olddir->dev
  1244.         && (ldir.index == finode
  1245.         || (dirmove && is_parent (ldir.index, finode, olddir->dev) > 0)))
  1246.     {
  1247.         Kfree (lpath);
  1248.         lpath=0;
  1249.     }
  1250.         
  1251. /* Create new entry */
  1252.       if((pos=search_dir(newname,newdir->index,newdir->dev,ADD))<0) return pos;
  1253. /* Delete old path */
  1254.     if((finode=search_dir(oldname,olddir->index,olddir->dev,KILL))<0)
  1255.             return finode;
  1256.     {
  1257.       unshort ino = finode;
  1258.       l_write (newdir->index, pos, 2L, &ino, newdir->dev);
  1259.     }
  1260.  
  1261. /* When moving directories, fixup things like '..' and nlinks of old and
  1262.  * new dirs
  1263.  */
  1264.  
  1265.     if(dirmove)
  1266.     {
  1267.         pos=search_dir("..",finode,newdir->dev,POS);
  1268.         if(pos<0) 
  1269.         {
  1270.             ALERT("m_rename: no .. in inode %ld",finode);
  1271.             return EACCDN;
  1272.         }
  1273.         if(pos!=DIR_ENTRY_SIZE*super_ptr[newdir->dev]->increment)
  1274.           ALERT("m_rename: Unexpected .. position in inode %ld",finode);
  1275.         {
  1276.           unshort ino = newdir->index;
  1277.           l_write (finode, pos, 2L, &ino, newdir->dev);
  1278.         }
  1279.         read_inode(olddir->index,&rip,olddir->dev);
  1280.         rip.i_nlinks--;
  1281.         write_inode(olddir->index,&rip,olddir->dev);
  1282.         read_inode(newdir->index,&rip,newdir->dev);
  1283.         rip.i_nlinks++;
  1284.         write_inode(newdir->index,&rip,newdir->dev);
  1285.     }
  1286.  
  1287.     if(cache_mode) l_sync();
  1288.  
  1289. /* Check the m_getname cache is not invalidated by this move ....
  1290.  * if no dir alter, invalidate if the ldir is the name being changed ,
  1291.  * if we alter dir's then if the moved dir is a parent of ldir, invalidate.
  1292.  */
  1293.  
  1294.     if (lpath && ldir.dev == olddir->dev
  1295.         && (ldir.index == finode
  1296.         || (dirren && is_parent (ldir.index, finode, olddir->dev) > 0)))
  1297.     {
  1298.         Kfree (lpath);
  1299.         lpath=0;
  1300.     }
  1301.  
  1302.     return 0;
  1303. }
  1304.  
  1305. /* Minix hard-link, you can't make a hardlink to a directory ... it causes
  1306.  * too much trouble, use symbolic links instead.
  1307.  */
  1308.  
  1309. long m_hardlink(fromdir,fromname,todir,toname)
  1310. fcookie *fromdir;
  1311. char *fromname;
  1312. fcookie *todir;
  1313. char *toname;
  1314. {
  1315.     long finode;
  1316.     d_inode rip;
  1317.     long pos;
  1318.  
  1319. /* Check cross drives */
  1320.     if(fromdir->dev!=todir->dev)return EXDEV;
  1321.  
  1322. /* Check new doesn't exist and path is otherwise valid */
  1323.     finode=search_dir(toname,todir->index,todir->dev,FIND);
  1324.     if(finode>0) return EACCDN;
  1325.     if(finode!=EFILNF) return finode;
  1326.  
  1327. /* Check old path OK */
  1328.     if((finode=search_dir(fromname,fromdir->index,fromdir->dev,FIND))<0)
  1329.         return finode;
  1330.  
  1331.     read_inode(finode,&rip,fromdir->dev);
  1332.     if( (!IS_REG(rip) && !IM_SPEC(rip.i_mode))
  1333.         || (rip.i_nlinks >=MINIX_MAX_LINK) ) return EACCDN;
  1334.  
  1335. /* Create new entry */
  1336.     if((pos=search_dir(toname,todir->index,todir->dev,ADD))<0) return pos;
  1337.     {
  1338.       unshort ino = finode;
  1339.       l_write (todir->index, pos, 2L, &ino, todir->dev);
  1340.     }
  1341.     rip.i_nlinks++;
  1342.     rip.i_ctime=Unixtime(Timestamp(),Datestamp());
  1343.     write_inode(finode,&rip,fromdir->dev);
  1344.  
  1345.     if(cache_mode) l_sync();
  1346.  
  1347.     return 0;
  1348. }
  1349.  
  1350. /* Symbolic links ... basically similar to a regular file with one zone */
  1351.  
  1352. long m_symlink(dir,name,to)
  1353. fcookie *dir;
  1354. char *name;
  1355. char *to;
  1356. {
  1357.     d_inode rip;
  1358.     long pos;
  1359.     unshort newinode;
  1360.  
  1361.     if(!*to)
  1362.     {
  1363.         DEBUG("m_symlink: invalid null filename");
  1364.         return EACCDN;
  1365.     }
  1366.  
  1367.     if(strlen(to)>=SYMLINK_NAME_MAX)
  1368.     {
  1369.         DEBUG("minixfs: Symbolic link name too long");        
  1370.         return ERANGE;
  1371.     }
  1372.  
  1373.     if((pos=search_dir(name,dir->index,dir->dev,ADD))<0) return pos;
  1374.  
  1375.     if(!(newinode=alloc_inode(dir->dev)))
  1376.     {
  1377.         DEBUG("minixfs: symlink drive %c,no free inodes",dir->dev+'A');
  1378.         return EACCDN;
  1379.     }
  1380.     
  1381.  
  1382.     bzero(&rip,sizeof(d_inode));
  1383.     rip.i_mode=I_SYMLINK | 0777;
  1384.     rip.i_size=strlen(to)+1;
  1385.     rip.i_uid=Getuid();
  1386.     rip.i_gid=Getgid();
  1387.     rip.i_mtime=Unixtime(Timestamp(),Datestamp());
  1388.     rip.i_ctime=rip.i_mtime;
  1389.     rip.i_atime=rip.i_mtime;
  1390.     rip.i_nlinks=1;
  1391.  
  1392.     if(!(rip.i_zone[0]=alloc_zone(dir->dev)))
  1393.     {
  1394.         free_inode(newinode,dir->dev);
  1395.         DEBUG("minixfs: symlink drive %c no free zones",dir->dev+'A');
  1396.         return EACCDN;
  1397.     }
  1398.     btos_cpy((char *)&temp,to);
  1399.      write_zone(rip.i_zone[0],&temp,dir->dev,&syscache);
  1400.     write_inode(newinode,&rip,dir->dev);
  1401.     l_write(dir->index,pos,2L,&newinode,dir->dev);
  1402.  
  1403.     if(cache_mode) l_sync();
  1404.  
  1405.     return 0;
  1406. }
  1407.  
  1408. long m_readlink(file,buf,len)
  1409. fcookie *file;
  1410. char *buf;
  1411. int len;
  1412. {
  1413.     long inum = file->index;
  1414.     d_inode rip;
  1415.  
  1416.     read_inode(inum,&rip,file->dev);
  1417.     if( (rip.i_mode & I_TYPE)!=I_SYMLINK)
  1418.     {
  1419.         DEBUG("minixfs: attempted readlink on non-symlink");
  1420.         return EACCDN;
  1421.     }
  1422.     read_zone(rip.i_zone[0],&temp,file->dev,&syscache);
  1423.     if(stob_ncpy(buf, (char *) &temp,len))
  1424.     {
  1425.         DEBUG("m_readlink: name too long");
  1426.         return ERANGE;
  1427.     }
  1428.     TRACE("m_readlink returned %s",buf);
  1429.  
  1430.     return 0;
  1431. }
  1432.  
  1433. /* the only settable attribute is FA_RDONLY; if the bit is set,
  1434.  * the mode is changed so that no write permission exists
  1435.  */
  1436. long m_chattr(file,attr)
  1437. fcookie *file;
  1438. int attr;
  1439. {
  1440.         long inum = file->index;
  1441.     int drive = file->dev;
  1442.     d_inode rip;
  1443.  
  1444.     if ( (attr & FA_RDONLY) ) {
  1445.         read_inode(inum,&rip,drive);
  1446.         rip.i_mode &= ~(0222);    /* turn off write permission */
  1447.         rip.i_ctime=Unixtime(Timestamp(),Datestamp());
  1448.         write_inode(inum,&rip,drive);
  1449.         if(cache_mode) l_sync();
  1450.     } else if (attr == 0) {
  1451.         read_inode(inum,&rip,drive);
  1452.         if ( (rip.i_mode & 0222) == 0 ) {
  1453.             rip.i_mode |= ( (rip.i_mode&0444) >> 1 );
  1454.                 /* turn write permission back on */
  1455.             rip.i_ctime=Unixtime(Timestamp(),Datestamp());
  1456.             write_inode(inum,&rip,drive);
  1457.             if(cache_mode) l_sync();
  1458.         }
  1459.     }
  1460.     return 0;
  1461. }
  1462.  
  1463. long m_pathconf(dir,which)
  1464. fcookie *dir;
  1465. int which;
  1466. {
  1467.     switch(which) {
  1468.     case -1:
  1469.         return DP_MAXREQ;
  1470.     case DP_IOPEN:
  1471.         return UNLIMITED;
  1472.     case DP_MAXLINKS:
  1473.          return MINIX_MAX_LINK;
  1474.     case DP_PATHMAX:
  1475.         return UNLIMITED; /* At last ! */
  1476.     case DP_NAMEMAX:
  1477.         return MMAX_FNAME(super_ptr[dir->dev]->increment);
  1478.     case DP_ATOMIC:
  1479.         return BLOCK_SIZE;    /* we can write at least a block atomically */
  1480.     case DP_TRUNC:
  1481.         return DP_AUTOTRUNC;
  1482.     case DP_CASE:
  1483.         return DP_CASESENS;    /* Well sort of ... */
  1484.     default:
  1485.         return EINVFN;
  1486.     }
  1487. }
  1488.  
  1489. long m_release(fc)
  1490. fcookie *fc;
  1491. {
  1492.     return 0;
  1493. }
  1494.  
  1495. long m_dupcookie(dest,src)
  1496. fcookie *dest,*src;
  1497. {
  1498.     unsigned tmpaux;
  1499.     tmpaux=dest->aux;
  1500.     *dest=*src;
  1501.     if(restore_dev!=-1 && 
  1502.     (tmpaux & (AUX_DEV|AUX_DRV))== restore_dev|AUX_DRV )
  1503.                         dest->dev = tmpaux & AUX_DEV;
  1504.  
  1505.     return 0;
  1506. }
  1507.